package javaInterview;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author Cyxan
 * @version 1.0
 */
public class ThreadPoolExample {
    public static void main(String[] args) {

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                3,
                8,
                5,
                java.util.concurrent.TimeUnit.SECONDS,
                new java.util.concurrent.LinkedBlockingQueue<Runnable>());

        for (int i = 0; i < 8 ; i++) {

            final int taskId = i;
            threadPoolExecutor.submit(() -> {
                System.out.println("Task " + taskId + " is running on thread " + Thread.currentThread().getName());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            });
        }
        // 关闭线程池
        threadPoolExecutor.shutdown();

        try {
            if(!threadPoolExecutor.awaitTermination(60, java.util.concurrent.TimeUnit.SECONDS)){

            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println("All tasks completed.");

        runOddEvenWithThreadPool();


    }

    private static void runOddEvenWithThreadPool() {
        // 构造打印器，约定输出 1-100 的奇偶数
        OddEvenPrinter printer = new OddEvenPrinter(100);

        // 使用固定大小线程池，仅创建两个线程分别处理奇数和偶数
        ThreadFactory factory = runnable -> {
            Thread thread = new Thread(runnable);
            thread.setDaemon(false);
            thread.setName(runnable instanceof OddTask ? "Odd-Worker" : "Even-Worker");
            return thread;
        };

        ExecutorService pool = Executors.newFixedThreadPool(2, factory);

        pool.submit(new OddTask(printer));
        pool.submit(new EvenTask(printer));

        pool.shutdown();
        try {
            if (!pool.awaitTermination(1, TimeUnit.MINUTES)) {
                pool.shutdownNow();
            }
        } catch (InterruptedException e) {
            pool.shutdownNow();
            Thread.currentThread().interrupt();
            throw new RuntimeException(e);
        }
    }

    /**
     * 利用 ReentrantLock + Condition 协调两个线程交替输出
     */
    private static class OddEvenPrinter {
        private final int max;
        private int current = 1;
        private final java.util.concurrent.locks.ReentrantLock lock = new java.util.concurrent.locks.ReentrantLock();
        private final java.util.concurrent.locks.Condition oddTurn = lock.newCondition();
        private final java.util.concurrent.locks.Condition evenTurn = lock.newCondition();

        private OddEvenPrinter(int max) {
            this.max = max;
        }

        private void printOdd() {
            while (true) {
                lock.lock();
                try {
                    while (current <= max && current % 2 == 0) {
                        oddTurn.await();
                    }
                    if (current > max) {
                        evenTurn.signal();
                        return;
                    }
                    System.out.println(Thread.currentThread().getName() + " 输出: " + current);
                    current++;
                    evenTurn.signal();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                } finally {
                    lock.unlock();
                }
            }
        }

        private void printEven() {
            while (true) {
                lock.lock();
                try {
                    while (current <= max && current % 2 != 0) {
                        evenTurn.await();
                    }
                    if (current > max) {
                        oddTurn.signal();
                        return;
                    }
                    System.out.println(Thread.currentThread().getName() + " 输出: " + current);
                    current++;
                    oddTurn.signal();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    return;
                } finally {
                    lock.unlock();
                }
            }
        }
    }

    private static class OddTask implements Runnable {
        private final OddEvenPrinter printer;

        private OddTask(OddEvenPrinter printer) {
            this.printer = printer;
        }

        @Override
        public void run() {
            printer.printOdd();
        }
    }

    private static class EvenTask implements Runnable {
        private final OddEvenPrinter printer;

        private EvenTask(OddEvenPrinter printer) {
            this.printer = printer;
        }

        @Override
        public void run() {
            printer.printEven();
        }
    }
}